home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / forth-to-latex-pretty-print / F2L / Modula-2 source / Forth2LaTeX.MOD next >
Encoding:
Text File  |  1994-12-19  |  30.2 KB  |  975 lines  |  [TEXT/MEDT]

  1. MODULE Forth2LaTeX;
  2.  
  3. (* Converts an input Forth program into a format fit for printing with LaTeX.
  4.  
  5.  
  6.    Copyright Ronald T. Kneusel, Oct. 15, 1994, all rights reserved.
  7.    
  8.    Internet: kneusel@studsys.mscs.mu.edu
  9.    
  10.    This code maybe distributed freely as long as all notices remain intact.
  11.    This code may not be distributed for profit without the written consent
  12.    of the author.
  13.    
  14.    
  15.    Last Mod:  12/19/94
  16.    
  17.    
  18.    Versions...
  19.    
  20.         *  (10-17-94)  ver. 1.0, no function name index or TOC
  21.         *  (10-17-94)  ver. 1.1, table of contents
  22.         *  (10-18-94)  ver. 1.2, function name index
  23.         *  (10-23-94)  ver. 1.3, header, date/time, latex, report/article
  24.                                  left margin, leftline
  25.         *  (10-23-94)  ver. 1.4, comments option, escape character, no comment
  26.         *  (11-01-94)  ver  1.5, shortened page setup, ^ character
  27.         *  (11-03-94)  ver. 1.6, line count LONGINT, 5 digits, left margin
  28.         *  (11-14-94)  ver. 1.7, multiple files (.f2l extension)
  29.         *  (12-19-94)  ver. 1.8, all options over-ridden by \ <opt> lines 
  30.         *  (12-19-94)  ver. 1.9, all user-defined words in index
  31.         
  32.   
  33.    ** What is this in?
  34.   
  35.   
  36.      This code runs as is under MacMETH Modula-2, a freely distributed
  37.      Modula-2 compiler available via FTP. (Try mac.archive.umich.edu)
  38.      It runs on any Macintosh, but should be readily portable to other
  39.      systems.  See the IMPORTed modules section for info about non-standard
  40.      modules.
  41.      
  42.      It spits out code that is compatible with LaTeX 2.09.  It works
  43.      with OzTeX 1.7 (ignore the \hbox errors).
  44.   
  45.   
  46.   
  47.    ** Notes for those who are interested in porting Forth2LaTeX....
  48.   
  49.    
  50.       Modula-2 is a decendant of Pascal and its syntax is nearly identical.
  51.       For some reason Wirth thought it necessary to split INTEGER into two
  52.       basic types... CARDINAL (positive integers) and INTEGER (just what
  53.       you'd expect).  Modula-2 uses CARDINALs for array indices and for
  54.       loop control.  VAL(<type>,<expr>) is the same as (<type>)<expr>
  55.       in C.  You will notice that there are many places where it was
  56.       necessary to cast INTEGERs as CARDINALs.
  57.       
  58.       Ignore the FROM ... IMPORT section.  It is used to import procedures
  59.       from Modula-2 libraries.
  60.       
  61.       Macintosh specifics are indicated throughout the code.  The only ones
  62.       that need a bit of explanation are: Lookup, GetFileName, and
  63.       PutFileName.  Lookup connects a file variable to a file name, the
  64.       FALSE indicates an existing file, TRUE indicates new or rewrite.
  65.       Modula-2 overloads the . operator, it acts as a field specifier as in
  66.       Pascal and it also acts as a module indicator should an entire
  67.       library be imported (as is the case with FileSystem, FileSystem.File
  68.       refers to the File "module" from the FileSystem library.)  As you
  69.       might have guessed, Modula-2 is case sensitive.  GetFileName and 
  70.       PutFileName call standard Macintosh SFGetFile and SFPutFile dialogs
  71.       to get a file name to open.  The "TEXT" in GetFileName specifies that
  72.       only items of type TEXT will be displayed in the dialog box.
  73.       
  74.       Strings are handled as null terminated character arrays. (0C = '\0'
  75.       numbers in octal).  A number of common string procedures are used
  76.       in the program.  A '|' is a case terminator in CASE statements.
  77.       
  78.       This should be easy to port to C or Pascal (especially Turbo).
  79.        
  80.    
  81. *)
  82.  
  83.  
  84. (*************************** Load Library Modules ****************************)
  85.  
  86. IMPORT FileSystem;
  87.  
  88. FROM FileUtil IMPORT GetFileName, PutFileName, Message, ExtLookup, Path,
  89.                      GetCurrentPath;
  90. FROM String IMPORT Append, Copy, Occurs, last, AppendCh, Length, Equal,
  91.                    Delete, Same, Assign;
  92. FROM Conversions IMPORT LongIntToString;
  93. FROM Menu IMPORT SetMenu, MenuRes, GetMenuCmd, InstallAboutProc, SetItem;
  94. FROM InOut IMPORT WriteString, WriteLn, Write, ReadString, WriteCard;
  95. FROM Storage IMPORT ALLOCATE,DEALLOCATE;
  96. FROM SYSTEM IMPORT VAL;
  97. FROM System IMPORT AddPath;
  98.  
  99. (* the following modules are not part of the standard MacMETH system *)
  100.  
  101. FROM IntlUtilities IMPORT IUDateString, IUTimeString;
  102. FROM MacTypes      IMPORT DateForm;
  103. FROM TimeManager   IMPORT GetDateTime;
  104.  
  105. (* they are included in the Modula-2 release for Mac, see the specific file
  106.    for installation instructions.  I did not write these modules and do not
  107.    know who did.  RTK *)
  108.  
  109. (************************* Data Type Declarations ****************************)
  110.  
  111. TYPE
  112.        string = ARRAY[0..511] OF CHAR;  (* should handle most cases *)
  113.        
  114.        str80 = ARRAY[0..79] OF CHAR;    (* for function names *)
  115.        
  116.        Ptr = POINTER TO FuncTableType;  (* for b-tree *)
  117.        
  118.        FuncTableType = RECORD
  119.                          right,left : Ptr;  (* standard binary tree *)
  120.                          name : str80;      (* function name *)
  121.                          line : CARDINAL;   (* line number of definition *)
  122.                        END;
  123.                        
  124. VAR
  125.        f, g, w, t : FileSystem.File;   (* file variables *)
  126.        done : BOOLEAN;                 (* menu handling & elsewhere *)
  127.        Command : MenuRes;              (* for menus *)
  128.        infile,outfile : string;        (* source & dest filenames *)
  129.        toc,up,index,bold,ra : BOOLEAN; (* settings flags *)
  130.        root : Ptr;                     (* beginning of tree *)
  131.        quote : BOOLEAN;                (* true in quoted strings *)
  132.        sections : BOOLEAN;             (* true if sectioning used *)
  133.        comments : BOOLEAN;             (* type of comment interpretation *)
  134.        noBracket : BOOLEAN;            (* used with \ . comments *)
  135.        FIRST : BOOLEAN;                (* multiple files *)
  136.        path : Path;                    (* path of files *)
  137.        out : string;
  138.        
  139.        
  140. PROCEDURE WriteTheString(VAR f:FileSystem.File; s:string);
  141. (* Write a string to disk *)
  142. VAR i:INTEGER;
  143. BEGIN
  144.   i:=0;
  145.   WHILE (i <= HIGH(s)) AND (s[i]<>0C) DO
  146.     FileSystem.WriteChar(f,s[i]);
  147.     INC(i);
  148.   END; (* WHILE *)
  149.   FileSystem.WriteChar(f,15C);
  150. END WriteTheString;
  151.  
  152. PROCEDURE ReadTheString(VAR f:FileSystem.File; VAR s:string; VAR done:BOOLEAN);
  153. (* Reads a string from a file, done TRUE for EOF(f) *)
  154. VAR i:CARDINAL;
  155.     ch : CHAR;
  156. BEGIN
  157.   i:=0;
  158.   FileSystem.ReadChar(f,ch);
  159.   WHILE (NOT f.eof) AND (ch<>15C) AND (i<=HIGH(s)) DO
  160.     s[i]:=ch;
  161.     INC(i);
  162.     FileSystem.ReadChar(f,ch);
  163.   END; (* WHILE *)
  164.   s[i]:=0C;
  165.   IF (i=0) AND (f.eof=TRUE) THEN
  166.     done:=TRUE;
  167.   END;
  168. END ReadTheString;
  169.  
  170. PROCEDURE GetTheDateTime(VAR date,time:string);
  171. (* Get the current date and time *)
  172. VAR numDate:LONGINT;
  173. BEGIN
  174.   GetDateTime(numDate);
  175.   IUDateString(numDate,abbrevDate,date);
  176.   IUTimeString(numDate,FALSE,time);
  177. END GetTheDateTime;
  178.  
  179. PROCEDURE Upper(VAR s:string);
  180. (* make s uppercase, does not change " " or \ ... *)
  181. VAR i:CARDINAL; quoted:BOOLEAN;
  182. BEGIN
  183.   quoted:=FALSE;  i:=0;
  184.   WHILE i <= VAL(CARDINAL,Length(s)) DO
  185.     IF s[i] = '\' THEN
  186.       i := VAL(CARDINAL,Length(s))+10;
  187.     END;
  188.     IF ~quoted THEN
  189.       s[i]:=CAP(s[i]);
  190.     END;
  191.     IF s[i]='"' THEN quoted:=~quoted; END;
  192.     INC(i);
  193.   END;
  194. END Upper;
  195.  
  196. PROCEDURE Upper0(VAR s:string);
  197. (* make uppercase *)
  198. VAR i:CARDINAL;
  199. BEGIN
  200.   FOR i:=0 TO VAL(CARDINAL,Length(s)) DO
  201.     s[i]:=CAP(s[i]);
  202.   END;
  203. END Upper0;
  204.  
  205. PROCEDURE New(VAR p:Ptr);
  206. (* simulate Pascal "new" *)
  207. BEGIN
  208.   ALLOCATE(p,SIZE(FuncTableType));
  209.   IF p=NIL THEN  (* out of memory! *)
  210.     Message("Fatal Error!  No more memory!","Click OK to exit.");
  211.     HALT;  (* force program to end *)
  212.   END;
  213. END New;
  214.  
  215. PROCEDURE Dispose(VAR p:Ptr);
  216. (* simulate Pascal "dispose" *)
  217. BEGIN
  218.   DEALLOCATE(p,SIZE(FuncTableType));
  219. END Dispose;
  220.  
  221. PROCEDURE LessThan(s,t:str80):BOOLEAN;  (* M2 doesn't have builtins for *)
  222. (* returns TRUE if s < t *)             (* lexical comparisons of strings *)
  223. VAR i,n : CARDINAL; b:BOOLEAN;
  224. BEGIN
  225.   IF Length(s)<=Length(t) THEN
  226.     n:=VAL(CARDINAL,Length(s));
  227.   ELSE
  228.     n:=VAL(CARDINAL,Length(t));
  229.   END;
  230.   i:=0;
  231.   WHILE (i<n) AND (ORD(s[i])=ORD(t[i])) DO
  232.     INC(i);
  233.   END;
  234.   IF (i=n) OR (ORD(s[i])>=ORD(t[i])) THEN
  235.     b:=FALSE;
  236.   ELSE
  237.     b:=TRUE;
  238.   END;
  239.   RETURN b;
  240. END LessThan;
  241.  
  242. PROCEDURE Insert(f:Ptr; VAR r:Ptr);    (* this is a standard function *)
  243. (* insert a tree node *)
  244. BEGIN
  245.   IF r=NIL THEN
  246.     r:=f;
  247.   ELSIF Equal(f^.name,r^.name) THEN
  248.     (* no duplicates *)
  249.   ELSIF LessThan(f^.name,r^.name) THEN
  250.     Insert(f,r^.left);
  251.   ELSE
  252.     Insert(f,r^.right);    
  253.   END;
  254. END Insert;
  255.  
  256. PROCEDURE AddName(n:str80; c:CARDINAL);
  257. (* add a name to the b-tree *)
  258. VAR p,r:Ptr;
  259. BEGIN
  260.   IF root=NIL THEN
  261.     New(root);
  262.     root^.name:=n;
  263.     root^.line:=c;
  264.     root^.right:=NIL;
  265.     root^.left:=NIL;
  266.   ELSE
  267.     r:=root;
  268.     New(p);
  269.     p^.name:=n;
  270.     p^.line:=c;
  271.     p^.right:=NIL;
  272.     p^.left:=NIL;
  273.     Insert(p,r);
  274.   END;
  275. END AddName;
  276.  
  277. (******** The following two procedures are Mac specific *****************)
  278.  
  279. PROCEDURE AboutThis;  (* display in Mac About under the apple menu *)
  280. (* give some info *)
  281. BEGIN
  282.   Message("** Forth2LaTeX 1.9 **","Ronald T. Kneusel, 1994.  This program is freeware.  Distribution of this program and accompanying files permitted as long as this notice is retained.");
  283. END AboutThis;
  284.  
  285. PROCEDURE InitMenus;
  286. (* install the menus and About proc *)
  287. VAR s:string;
  288. BEGIN
  289.   SetMenu(1,"File|Open.../O|(-|Quit/Q");
  290.   SetMenu(2,"Edit|(Cut/X|(Copy/C|(Paste/V|(-|(Clear");
  291.   s:="Settings|Force uppercase is OFF/U|(-|Create TOC is OFF/T";
  292.   Append(s,"|Create index is OFF/I|(-|Bold names is ON/B");
  293.   Append(s,"|(-|Style is ARTICLE/S|(-|Comments are FORTH");
  294.   SetMenu(3,s);
  295.   toc:=FALSE; up:=FALSE; index:=FALSE; bold:=TRUE;  ra:=FALSE; sections:=FALSE;
  296.   comments:=FALSE;
  297.   InstallAboutProc("About Forth2LaTeX...",AboutThis);
  298. END InitMenus;
  299.  
  300. (********** End Mac specific ********************)
  301.  
  302. PROCEDURE StripSuffix(s:string; VAR w:string);
  303. (* strips the file suffix if present *)
  304. VAR i:INTEGER; t:string;
  305. BEGIN
  306.   t:=s;
  307.   Upper(t);
  308.   i:=Occurs(t,0,'.4TH');
  309.   IF i<>last THEN
  310.     Copy(w,s,0,i);
  311.   ELSE
  312.     i:=Occurs(t,0,'.FORTH');
  313.     IF i<>last THEN
  314.       Copy(w,s,0,i);
  315.     ELSE
  316.       i:=Occurs(t,0,'.FTH');
  317.       IF i<>last THEN
  318.         Copy(w,s,0,i);
  319.       ELSE
  320.         w:=s;
  321.       END;
  322.     END;
  323.   END;
  324. END StripSuffix;
  325.  
  326. PROCEDURE Header;
  327. (* display a header *)
  328. BEGIN
  329.   Write(14C);
  330.   WriteString("** Forth2LaTeX 1.9 **    ");
  331.   WriteString("Ronald T. Kneusel, 1994.  This program is freeware."); WriteLn;
  332.   WriteString("                         Choose 'Open...' from the 'File' menu to begin.");
  333.   WriteLn; WriteLn;
  334. END Header;
  335.  
  336. PROCEDURE GetProgramInfo;
  337. (* get the title page info *)
  338. VAR done,ok:BOOLEAN; str,prog,auth,start,modif,modby,sum,t:string;
  339.     n:CARDINAL;  c:LONGINT;
  340. BEGIN
  341.   done:=FALSE;
  342.   prog:=""; auth:=""; start:=""; modif:=""; modby:=""; sum:="";
  343.   c:=1;
  344.   ReadTheString(f,str,done);
  345.   WHILE ~done DO
  346.     IF Occurs(str,0,"\ Program:")<>last THEN
  347.       n:=Occurs(str,0,"\ Program:");
  348.       Delete(str,0,n+10); prog:=str;
  349.     ELSIF Occurs(str,0,"\ Author:")<>last THEN
  350.       n:=Occurs(str,0,"\ Author:");
  351.       Delete(str,0,n+9); auth:=str;
  352.     ELSIF Occurs(str,0,"\ Started:")<>last THEN
  353.       n:=Occurs(str,0,"\ Started:");
  354.       Delete(str,0,n+10); start:=str;
  355.     ELSIF Occurs(str,0,"\ Modified:")<>last THEN
  356.       n:=Occurs(str,0,"\ Modified:");
  357.       Delete(str,0,n+11); modif:=str;
  358.     ELSIF Occurs(str,0,"\ Modify By:")<>last THEN
  359.       n:=Occurs(str,0,"\ Modify By:");
  360.       Delete(str,0,n+12); modby:=str;
  361.     ELSIF Occurs(str,0,"\ Summary:")<>last THEN
  362.       n:=Occurs(str,0,"\ Summary:");
  363.       Delete(str,0,n+10); sum:=str;
  364.     ELSIF Occurs(str,0,"\ Comments:")<>last THEN
  365.       IF Occurs(str,0,"LATEX")<>last THEN
  366.         comments:=TRUE;
  367.       ELSIF Occurs(str,0,"FORTH")<>last THEN
  368.         comments:=FALSE;
  369.       END;
  370.     ELSIF Occurs(str,0,"\ Uppercase:")<>last THEN
  371.       IF Occurs(str,0,"ON")<>last THEN
  372.         up:=TRUE;
  373.       ELSIF Occurs(str,0,"OFF")<>last THEN
  374.         up:=FALSE;
  375.       END;
  376.     ELSIF Occurs(str,0,"\ Table of Contents:")<>last THEN
  377.       IF Occurs(str,0,"ON")<>last THEN
  378.         toc:=TRUE;
  379.       ELSIF Occurs(str,0,"OFF")<>last THEN
  380.         toc:=FALSE;
  381.       END;
  382.     ELSIF Occurs(str,0,"\ Index:")<>last THEN
  383.       IF Occurs(str,0,"ON")<>last THEN
  384.         index:=TRUE;
  385.       ELSIF Occurs(str,0,"OFF")<>last THEN
  386.         index:=FALSE;
  387.       END;
  388.     ELSIF Occurs(str,0,"\ Bold:")<>last THEN
  389.       IF Occurs(str,0,"ON")<>last THEN
  390.         bold:=TRUE;
  391.       ELSIF Occurs(str,0,"OFF")<>last THEN
  392.         bold:=FALSE;
  393.       END;
  394.     ELSIF Occurs(str,0,"\ Style:")<>last THEN
  395.       IF Occurs(str,0,"REPORT")<>last THEN
  396.         ra:=TRUE;
  397.       ELSIF Occurs(str,0,"ARTICLE")<>last THEN
  398.         ra:=FALSE;
  399.       END;
  400.     END;
  401.     ReadTheString(f,str,done);
  402.     IF (Occurs(str,0,"ection:")=last) OR (Occurs(str,0,"hapter:")=last) THEN
  403.       INC(c);
  404.     END;
  405.   END;
  406.   str:="\title{{\bf "; Append(str,prog); Append(str,"}}");
  407.   WriteTheString(g,str);
  408.   str:="\author{{\small "; Append(str,auth); Append(str,"}}");
  409.   WriteTheString(g,str);
  410.   WriteTheString(g,"\date{{\small \today}}");
  411.   WriteTheString(g,"\maketitle");
  412.   WriteTheString(g,"\vspace{4in} \hfil \break {\large{\bf Program Information:}} \hfil \break");
  413.   WriteTheString(g,"\hfil \break");
  414.   str:="{\bf Summary:}\ \ "; Append(str,sum); Append(str,"\hfil \break");
  415.   WriteTheString(g,str);
  416.   str:="{\bf Author:}\ \ "; Append(str,auth); Append(str,"\hfil \break");
  417.   WriteTheString(g,str);
  418.   str:="{\bf Modified:}\ \ "; Append(str,modif); Append(str,"\hfil \break");
  419.   WriteTheString(g,str);
  420.   str:="{\bf Modify by:}\ \ "; Append(str,modby); Append(str,"\hfil \break");
  421.   WriteTheString(g,str);
  422.   LongIntToString(c-LONG(1),5,5,10,t,ok);
  423.   str:="{\bf Lines:}\ \ "; Append(str,t); Append(str,"\hfil \break \clearpage");
  424.   WriteTheString(g,str);
  425. END GetProgramInfo;
  426.  
  427. PROCEDURE CopyHeader;
  428. (* setup the document *)
  429. VAR s:string;
  430. BEGIN
  431.   s:="\documentstyle[12pt]{";
  432.   IF ra THEN Append(s,"report}"); ELSE Append(s,"article}"); END;
  433.   WriteTheString(g,s);
  434.   WriteTheString(g,"\voffset=-0.8in");
  435.   WriteTheString(g,"\hoffset=-0.5in");
  436.   WriteTheString(g,"\textheight=9in");
  437.   WriteTheString(g,"\textwidth=6.5in");
  438.   WriteTheString(g,"\parindent= 0pt");
  439.   WriteTheString(g,"\begin{document}");
  440.   WriteTheString(g,"\pagestyle{plain}");
  441.   WriteTheString(g,"\pagenumbering{roman}");
  442. END CopyHeader;
  443.  
  444. PROCEDURE HandleComment(VAR i:CARDINAL; str:string; VAR out:string);
  445. (* process the comment part of a string *)
  446. VAR q:CARDINAL; latex:BOOLEAN;
  447. BEGIN
  448.   Delete(str,0,i);  (* remove leading characters *)
  449.   IF str[2]='.' THEN  (* \ . comment *)
  450.     Delete(str,0,3);  
  451.     out:=str;
  452.     noBracket:=TRUE;
  453.   ELSE
  454.    Append(out,"}{\it");  latex:=FALSE;
  455.    IF ~comments THEN
  456.      FOR q:=0 TO VAL(CARDINAL,Length(str))-1 DO
  457.        IF ~latex THEN
  458.           CASE str[q] OF
  459.            ' ' : Append(out,"\ ");
  460.           |'_' : Append(out,"\_");
  461.           |11C : Append(out,"\ \ \ \ ");
  462.           |'\' : Append(out,"$\backslash$");(* LaTeX makes use of a number of *)
  463.           |'#' : Append(out,"\#");          (* characters that must be escaped *)
  464.           |'&' : Append(out,"\&");          (* before use. *)
  465.           |'$' : Append(out,"\$");
  466.           |'%' : Append(out,"\%");
  467.           |'}' : Append(out,"\}");
  468.           |'{' : Append(out,"\{");
  469.           |'<' : Append(out,"$<$");
  470.           |'>' : Append(out,"$>$");
  471.           |'^' : Append(out,"$\uparrow$");
  472.           |'`' : latex:=~latex;    (* ` (backquote) is LaTeX escape *)
  473.           |'~' : Append(out,"$\tilde{ }$");
  474.          ELSE
  475.            AppendCh(out,str[q]);
  476.          END;
  477.       ELSE
  478.         IF str[q] <> '`' THEN
  479.           AppendCh(out,str[q]);
  480.         ELSE
  481.           latex:=~latex;
  482.         END;
  483.      END;
  484.     END;
  485.    ELSE
  486.      Append(out,str);  (* LATEX comments mode, do not interpret *)
  487.    END;
  488.   END;
  489.   i:=65534; (* force loop to quit *)
  490. END HandleComment;
  491.  
  492. PROCEDURE HandleFunction(VAR i:CARDINAL; str:string; VAR out:string; c:LONGINT);
  493. (* Process function definition *)
  494.  
  495. (* N.B. This is not a rigorous procedure. If the program contains code
  496.    of the form : ( -- ) name, or if there is anything other than spaces
  497.    between the : and the name, it bombs.  In practice, this is not a serious
  498.    restriction.
  499. *)
  500.  
  501. VAR q,old,s,k:CARDINAL; name:str80; t,w:string;
  502. BEGIN
  503.   IF (((i>0) AND (str[i-1]=' ') AND (str[i+1]=' ')) OR
  504.      ((i=0) AND (str[1]=' '))) AND ~quote THEN
  505.     IF bold OR index THEN (* if no index or bold requested continue *)
  506.       old:=i; (* remeber where we are *)
  507.       INC(i);  (* move past the : *)
  508.       WHILE (i<VAL(CARDINAL,Length(str))) AND (str[i]=' ') DO
  509.         INC(i);  (* skip spaces *)
  510.       END;
  511.       s:=i;
  512.       WHILE (i<VAL(CARDINAL,Length(str))) AND (str[i]<>' ') DO
  513.         INC(i);
  514.       END;
  515.       Copy(w,str,s,i-s);  (* get the function name *)
  516.       IF up THEN
  517.         Assign(t,w);
  518.         Upper(t);
  519.         Assign(w,t);
  520.       END;
  521.       name:="";
  522.       FOR k:=0 TO VAL(CARDINAL,Length(w))-1 DO  (* check for special chars *)
  523.         CASE w[k] OF
  524.            ' ' : Append(name,"\ ");
  525.           |'_' : Append(name,"\_");
  526.           |11C : Append(name,"\ \ \ \ ");
  527.           |'\' : Append(name,"$\backslash$");  
  528.           |'#' : Append(name,"\#");           
  529.           |'&' : Append(name,"\&");          
  530.           |'$' : Append(name,"\$");
  531.           |'%' : Append(name,"\%");
  532.           |'}' : Append(name,"\}");
  533.           |'{' : Append(name,"\{");
  534.           |'<' : Append(name,"$<$");
  535.           |'>' : Append(name,"$>$");
  536.           |'^' : Append(name,"$\uparrow$");
  537.           |'~' : Append(name,"$\tilde{ }$");
  538.         ELSE
  539.           AppendCh(name,w[k]);
  540.         END;
  541.       END;
  542.       AddName(name,c);  (* add to the tree *)
  543.       IF bold THEN
  544.         Append(out,":\ {\bf ");
  545.         Append(out,name);
  546.         Append(out,"}\ ");  (* leave i where it is *)
  547.       ELSE
  548.         Append(out,":");
  549.         i:=old;  (* continue from where we left off *)
  550.       END;
  551.     ELSE
  552.       Append(out,":");
  553.     END;
  554.   ELSE
  555.     Append(out,":");
  556.   END;
  557. END HandleFunction;
  558.  
  559. PROCEDURE ProcessString(str:string; VAR out:string; VAR c:LONGINT);
  560. (* process a single string, character by character *)
  561. VAR t,s:string;  i:CARDINAL;  ok:BOOLEAN;
  562. BEGIN
  563.   noBracket:=FALSE;
  564.   out:="\leftline{{\tt";
  565.   LongIntToString(c,5,5,10,t,ok);  (* make c into a right justified string *)
  566.   s:="";
  567.   FOR i:=0 TO 4 DO
  568.     IF t[i]=' ' THEN           (* make spaces into zeros *)
  569.       Append(s,"0");
  570.     ELSE
  571.       AppendCh(s,t[i]);
  572.     END;
  573.   END;
  574.   Append(out,s); Append(out,"\ -\ ");
  575.   i:=0; quote:=FALSE;
  576.   WHILE i < VAL(CARDINAL,Length(str)) DO
  577.     CASE str[i] OF
  578.       ' ' : Append(out,"\ ");         (* force blanks to show *)
  579.      |'_' : Append(out,"\_");
  580.      |11C : Append(out,"\ \ \ \ ");   (* tabs -> 4 spaces *)
  581.      |'\' : HandleComment(i,str,out); (* comment found *)
  582.      |'#' : Append(out,"\#");         (* characters used by LaTeX *)
  583.      |'&' : Append(out,"\&");
  584.      |'$' : Append(out,"\$");
  585.      |'%' : Append(out,"\%");
  586.      |'}' : Append(out,"\}");
  587.      |'{' : Append(out,"\{");
  588.      |'~' : Append(out,"$\tilde{ }$");
  589.      |'^' : Append(out,"$\uparrow$");
  590.      |':' : HandleFunction(i,str,out,c); (* function definition? *)
  591.      |'"' : Append(out,'"'); quote:=~quote;  (* toggle string quote flag *)
  592.     ELSE
  593.       IF str[i] > ' ' THEN   (* not a control character *)
  594.         IF ~up OR quote THEN
  595.           AppendCh(out,str[i]);
  596.         ELSE
  597.           AppendCh(out,CAP(str[i]));
  598.         END;
  599.       END;
  600.     END; (* case *)
  601.     INC(i);
  602.   END; (* while *)
  603.   IF ~noBracket THEN
  604.     Append(out,"}}");
  605.     noBracket:=FALSE;  (* this line shouldn't have a }} at the end *)
  606.   END;
  607. END ProcessString;
  608.  
  609. PROCEDURE MoreProcessString(str:string; VAR out:string;c:LONGINT);
  610. (* handle VARIABLE, CONSTANT, and CREATE words *)
  611. VAR  ucStr,s:string; n,i:CARDINAL; f,ff:BOOLEAN; name:str80;
  612. BEGIN
  613.   IF Same(str,0,9,"\leftline") THEN
  614.     Delete(str,Length(str)-2,2);  (* remove }} *)
  615.     Append(str,"\ ");             (* add and extra space *)
  616.     ucStr:=str;  Upper0(ucStr);  out:="";
  617.     REPEAT
  618.       f:=FALSE;
  619.       i:=Occurs(str,0,"{\it$\backslash");  (* position of comment *)
  620.       IF Occurs(ucStr,0," CREATE\ ")<>last THEN
  621.         n:=Occurs(ucStr,0," CREATE")+7; f:=TRUE;
  622.       ELSIF Occurs(ucStr,0," VARIABLE")<>last THEN
  623.         n:=Occurs(ucStr,0," VARIABLE")+9; f:=TRUE;
  624.       ELSIF Occurs(ucStr,0," CONSTANT")<>last THEN
  625.         n:=Occurs(ucStr,0," CONSTANT")+9; f:=TRUE;
  626.       ELSIF Occurs(ucStr,0," FVARIABLE")<>last THEN
  627.         n:=Occurs(ucStr,0," FVARIABLE")+10; f:=TRUE;
  628.       ELSIF Occurs(ucStr,0," FCONSTANT")<>last THEN
  629.         n:=Occurs(ucStr,0," FCONSTANT")+10; f:=TRUE;
  630.       END;
  631.       IF (n>=i) THEN  f:=FALSE;  END;
  632.       IF f THEN
  633.         Copy(s,str,0,n);  Append(out,s);  (* add to output string *)
  634.         (* get name from str *)
  635.         Delete(str,0,n);  Delete(ucStr,0,n);
  636.         REPEAT
  637.          ff:=FALSE;
  638.          IF Same(str,0,2,"\ ") THEN
  639.            Delete(str,0,2);  Delete(ucStr,0,2);
  640.            Append(out,"\ ");
  641.            ff:=TRUE;
  642.          END;
  643.         UNTIL NOT ff;
  644.         n:=Occurs(str,0,"\ ");
  645.         Copy(name,str,0,n);  (* get the name *)
  646.         Append(out,"{\sf ");
  647.         Append(out,name);
  648.         Append(out,"}");
  649.         Delete(str,0,n); Delete(ucStr,0,n);
  650.         (* add to name list *)
  651.         AddName(name,c);
  652.       END;
  653.     UNTIL NOT f;
  654.     Append(out,str);             (* add end of the string *)
  655.     Delete(out,Length(out)-2,2); (* remove final \ *)
  656.     Append(out,"}}");            (* add final }} *)
  657.   ELSE
  658.     out:=str;   (* not a program line, do nothing *)
  659.   END;
  660. END MoreProcessString;
  661.  
  662. PROCEDURE OutputIndex;
  663. (* prints an index of function names *)
  664. VAR  out:string; i,q,lineCount:CARDINAL;
  665.  
  666.   PROCEDURE Display(s:str80; c:CARDINAL);
  667.   (* display a node in the tabbing environment *)
  668.   VAR t,w:str80;  ok:BOOLEAN;  j:CARDINAL;
  669.   BEGIN
  670.     Append(out,"{\rm "); Append(out,s); Append(out,"}\ {\tt (");
  671.     LongIntToString(c,5,5,10,t,ok); w:="";
  672.     FOR j:=0 TO 4 DO
  673.       IF t[j]=' ' THEN
  674.         AppendCh(w,'0');
  675.       ELSE
  676.         AppendCh(w,t[j]);
  677.       END;
  678.     END;  Append(out,w);
  679.     IF i<2 THEN
  680.       Append(out,")} & ");
  681.       INC(i);
  682.     ELSE
  683.       i:=0; Append(out,")} \\");
  684.       WriteTheString(g,out);
  685.       out:="";  INC(lineCount);
  686.       IF lineCount>45 THEN
  687.         WriteTheString(g,"\end{tabular}");
  688.         WriteTheString(g,"\clearpage");
  689.         WriteTheString(g,"\begin{tabular}{lllll}");
  690.         lineCount:=0;
  691.       END;
  692.     END;
  693.   END Display;
  694.  
  695.   PROCEDURE WalkTree(p:Ptr);
  696.   (* Inorder tree traversal to display user-defined names *)
  697.   BEGIN
  698.     IF p<>NIL THEN
  699.       WalkTree(p^.left);
  700.       Display(p^.name,p^.line);
  701.       WalkTree(p^.right);
  702.     END;
  703.   END WalkTree;
  704.  
  705. BEGIN
  706.   out:=""; i:=0; lineCount:=0;
  707.   IF ~ra OR (ra AND ~toc) THEN  (* article *)
  708.    WriteTheString(g,"\clearpage");
  709.    IF sections THEN  (* user had a \ Section: statement *)
  710.      WriteTheString(g,"\section{Index} \vspace{0.5in}");
  711.    ELSE
  712.    WriteTheString(g,"\begin{center} {\huge Index} \end{center} \vspace{0.5in}");
  713.    END;
  714.    WriteTheString(g,"\vspace{0.5in}");
  715.    WriteTheString(g,"\hfil \break");
  716.   ELSE         (* report *)
  717.    WriteTheString(g,"\appendix");
  718.    WriteTheString(g,"\chapter{Index of User-Defined Names}");
  719.   END;
  720.   WriteTheString(g,"\begin{tabular}{lllll}");
  721.   WalkTree(root);
  722.   IF i<>0 THEN
  723.     FOR q:=1 TO 3-(i+1) DO   (* fill in last row if necessary *)
  724.       Append(out," & ");
  725.     END;
  726.     Append(out," \\");
  727.     WriteTheString(g,out);  
  728.   END; 
  729.   WriteTheString(g,"\end{tabular}");
  730. END OutputIndex;
  731.  
  732. PROCEDURE Convert(infile:string; VAR count:LONGINT);
  733. (* transform a Forth source code file into LaTeX *)
  734. VAR str,out,date,time:string; done:BOOLEAN; n:CARDINAL;
  735. BEGIN
  736.   IF FIRST THEN
  737.     CopyHeader;                      (* setup the file *)
  738.     GetProgramInfo;                  (* get author, etc. *)
  739.     IF toc THEN
  740.       WriteTheString(g,"\tableofcontents \clearpage");
  741.     END;
  742.     WriteTheString(g,"\pagestyle{plain}");
  743.     WriteTheString(g,"\pagenumbering{arabic}");
  744.     WriteTheString(g,"\setcounter{page}{1}");
  745.     WriteTheString(g,"\small");
  746.     FileSystem.Close(f);
  747.     FIRST:=FALSE;
  748.     FileSystem.Lookup(f,infile,FALSE);  (* re-open the file *)
  749.     count:=0;
  750.   END;
  751.   done:=FALSE;
  752.   ReadTheString(f,str,done);
  753.   WHILE ~done DO
  754.     IF (Occurs(str,0,"\ Section:")<>last) AND toc THEN
  755.       n:=Occurs(str,0,"\ Section:");
  756.       Delete(str,0,n+10);
  757.       out:="\section{"; Append(out,str); Append(out,"}");
  758.       sections:=TRUE;
  759.     ELSIF (Occurs(str,0,"\ Subsection:")<>last) AND toc THEN
  760.       n:=Occurs(str,0,"\ Subsection:");
  761.       Delete(str,0,n+13);
  762.       out:="\subsection{"; Append(out,str); Append(out,"}");
  763.     ELSIF (Occurs(str,0,"\ Subsubsection:")<>last) AND toc THEN
  764.       n:=Occurs(str,0,"\ Subsubsection:");
  765.       Delete(str,0,n+16);
  766.       out:="\subsubsection{"; Append(out,str); Append(out,"}");
  767.     ELSIF Same(str,0,8,"\ latex:") THEN
  768.       Delete(str,0,8);  WriteTheString(g,str);  (* LaTeX command *)
  769.     ELSIF ra AND toc AND (Occurs(str,0,"\ Chapter:")<>last) THEN
  770.       n:=Occurs(str,0,"\ Chapter:");
  771.       Delete(str,0,n+10);
  772.       out:="\chapter{"; Append(out,str); Append(out,"}");
  773.     ELSE
  774.       ProcessString(str,out,count);  (* convert a single line *)
  775.       str:=out;
  776.       MoreProcessString(str,out,count);  (* handle vars and constants *)
  777.       INC(count);
  778.     END;
  779.     WriteTheString(g,out);
  780.     ReadTheString(f,str,done);
  781.   END; (* while *)
  782. END Convert;
  783.  
  784. PROCEDURE KillTree(VAR p:Ptr);
  785. (* Postorder traversal to kill the tree *)
  786. BEGIN
  787.   IF p<>NIL THEN
  788.     KillTree(p^.left);
  789.     KillTree(p^.right);
  790.     Dispose(p);
  791.   END;
  792. END KillTree;
  793.  
  794. PROCEDURE UpdateCount(c,outfile:string);
  795. (* Kludge to update the count when using multiple files *)
  796. VAR done:BOOLEAN; str,t:string;
  797. BEGIN
  798.   done:=FALSE;
  799.   FileSystem.Lookup(f,outfile,FALSE);
  800.   str:="RTK101266.tmp"; AddPath(path,str,t);
  801.   FileSystem.Lookup(g,t,TRUE);
  802.   ReadTheString(f,str,done);
  803.   WHILE ~done DO
  804.     IF Occurs(str,0,"{\bf Lines:}")<>last THEN
  805.       str:="{\bf Lines:}\ \ ";  Append(str,c);
  806.       Append(str," \hfil \break \clearpage");
  807.     END;
  808.     WriteTheString(g,str);
  809.     ReadTheString(f,str,done);
  810.   END;
  811.   FileSystem.Close(f);
  812.   FileSystem.Lookup(f,outfile,FALSE);
  813.   FileSystem.Delete(f);
  814.   FileSystem.Close(g);
  815.   FileSystem.Lookup(g,t,FALSE);
  816.   FileSystem.Rename(g,outfile);
  817.   FileSystem.Close(g); 
  818. END UpdateCount;
  819.  
  820. PROCEDURE CommandFile(cmdfile:string);
  821. (* process a command file, '.f2l' suffix *)
  822. VAR done,skip,b:BOOLEAN;  str,outfile,infile,t:string;
  823.     n,i:CARDINAL; c:LONGINT;
  824. BEGIN
  825.   ExtLookup(w,cmdfile,FALSE,b);
  826.   done:=FALSE;  t:="a.tex"; (* default name *)
  827.   GetCurrentPath(path);  AddPath(path,t,outfile);
  828.   ReadTheString(w,str,done);
  829.   WHILE ~done DO
  830.     IF Occurs(str,0,"# Output: ")<>last THEN
  831.       n:=Occurs(str,0,"# Output: ");
  832.       Delete(str,0,n+10);
  833.       AddPath(path,str,outfile);
  834.       done:=TRUE;
  835.     END;
  836.     ReadTheString(w,str,done);
  837.   END;
  838.   FileSystem.Close(w);
  839.   FileSystem.Lookup(g,outfile,TRUE);
  840.   FileSystem.Lookup(w,cmdfile,FALSE);
  841.   c:=0;       WriteLn; WriteLn;
  842.   done:=FALSE;  FIRST:=TRUE;  (* flag first file *)
  843.   ReadTheString(w,str,done);
  844.   WHILE ~done DO
  845.     skip:=FALSE;  infile:="";
  846.     IF ~Equal(str,"") THEN
  847.       n:=0;
  848.       WHILE (str[n]=' ') OR (str[n]=11C) DO
  849.         INC(n);
  850.       END;
  851.       FOR i:= n TO VAL(CARDINAL,Length(str))-1 DO
  852.         IF (str[i]<>'#') AND ~skip AND (str[i]<>' ') THEN
  853.           AppendCh(infile,str[i]);
  854.         ELSE
  855.           skip:=TRUE;
  856.         END;
  857.       END;
  858.     END;
  859.     IF ~Equal(infile,"") THEN  (* process this file *)
  860.       AddPath(path,infile,t);  infile:=t;
  861.       FileSystem.Lookup(f,infile,FALSE);
  862.       WriteString("    "); WriteString(infile); WriteLn;
  863.       Convert(infile,c);
  864.       FileSystem.Close(f);
  865.     END;
  866.     ReadTheString(w,str,done);  (* get next file *)
  867.   END;
  868.   IF index THEN
  869.     OutputIndex; (* create the index *)
  870.   END;
  871.   WriteTheString(g,"\end{document}");
  872.   FileSystem.Close(g);  FileSystem.Close(w);
  873.   LongIntToString(c-LONG(1),5,5,10,t,b);
  874.   UpdateCount(t,outfile);
  875.   WriteLn; WriteLn;
  876.   WriteString(t); WriteString(" lines total.");
  877. END CommandFile;
  878.  
  879. PROCEDURE ConvertFile;
  880. (* get the source and dest files and convert *)
  881. VAR ok,b:BOOLEAN; c:LONGINT; t:string;
  882. BEGIN
  883.   WriteString("Input ?"); WriteLn;
  884.   GetFileName(infile,"TEXT",ok);
  885.   IF ok THEN
  886.     IF (Occurs(infile,0,".f2l")<>last) OR (Occurs(infile,0,".F2L")<>last) THEN
  887.       CommandFile(infile);
  888.     ELSE
  889.       StripSuffix(infile,outfile);  Append(outfile,".tex");
  890.       WriteString("Output ?"); WriteLn;
  891.       PutFileName(outfile,ok);
  892.       IF ok THEN
  893.         WriteLn; WriteLn;
  894.         WriteString("Starting conversion..."); WriteLn; WriteLn;
  895.         FileSystem.Lookup(g,outfile,TRUE);  (* dest *)
  896.         FIRST:=TRUE;
  897.         FileSystem.Lookup(f,infile,FALSE);
  898.         Convert(infile,c);
  899.         IF index THEN
  900.           OutputIndex; (* create the index *)
  901.         END;
  902.         FileSystem.Close(f);
  903.         WriteTheString(g,"\end{document}");
  904.         FileSystem.Close(g);
  905.         LongIntToString(c,5,5,10,t,b);
  906.         WriteString("... Conversion complete. ");
  907.         WriteString(t);  WriteString(" lines.");
  908.       END;
  909.     END;
  910.   END;
  911.   IF ~ok THEN Header; END;
  912.   KillTree(root); root:=NIL;  (* remove existing tree if any *)
  913. END ConvertFile;
  914.  
  915. PROCEDURE Toggle(VAR b:BOOLEAN; c:CARDINAL; s:str80);
  916. (* change a Settings menu setting *)
  917. VAR
  918. BEGIN
  919.   IF b THEN
  920.     b:=FALSE;
  921.     CASE c OF
  922.       8 : Append(s,"ARTICLE");
  923.      |10: Append(s,"FORTH");
  924.     ELSE 
  925.       Append(s,"OFF");
  926.     END;
  927.   ELSE
  928.     b:=TRUE;
  929.     CASE c OF
  930.       8 : Append(s,"REPORT");
  931.      |10: Append(s,"LATEX");
  932.     ELSE 
  933.       Append(s,"ON");
  934.     END;
  935.   END;
  936.   SetItem(3,c,s);
  937. END Toggle;
  938.  
  939.  
  940. (* MAIN *)
  941.  
  942. (* Most of the code here is Mac, it controls the menus and responds to
  943.    user selections.  The first line after BEGIN makes the output files
  944.    of the right type and creator for use with Pete Keleher's "Alpha" text
  945.    editor.
  946. *)
  947.  
  948. BEGIN
  949.   FileSystem.SetDefltFileType("TEXT","ALFA"); (* setup for Alpha editor *)
  950.   InitMenus;
  951.   Header; root:=NIL;
  952.   LOOP
  953.     GetMenuCmd(Command,done);
  954.     IF done THEN
  955.       CASE Command.menuID OF
  956.         1 : CASE Command.menuCmd OF                (* File Menu *)
  957.               1 : Header; ConvertFile;  (* open *)
  958.              |3 : EXIT;                 (* quit *)
  959.             END;
  960.        |2 : (* Edit menu, unused, 
  961.               present for desk accessories *)
  962.        |3 : CASE Command.menuCmd OF                (* Settings Menu *)
  963.               1 : Toggle(up,1,"Force uppercase is ");
  964.              |3 : Toggle(toc,3,"Create TOC is ");
  965.              |4 : Toggle(index,4,"Create index is ");
  966.              |6 : Toggle(bold,6,"Bold names is ");
  967.              |8 : Toggle(ra,8,"Style is ");
  968.              |10: Toggle(comments,10,"Comments are ");
  969.             END; (* case *)
  970.       END; (* case *)
  971.     END; (* if *)
  972.   END; (* loop *)
  973.   FileSystem.SetDefltFileType("TEXT","MEDT"); (* set to Modula-2 again *)
  974. END Forth2LaTeX.